package com.jumper.study.admin.service.impl;

import java.time.LocalDate;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.jumper.study.admin.dto.req.EducationSearchReq;
import com.jumper.study.admin.service.StudentLessonLogService;
import com.jumper.study.admin.service.StudentLessonService;
import com.jumper.study.common.api.SortField;
import com.jumper.study.common.api.SortType;
import com.jumper.study.db.dao.StudentLessonMapper;
import com.jumper.study.db.dto.StudentLessonDto;
import com.jumper.study.db.dto.StudentLessonSearchDto;
import com.jumper.study.admin.dto.req.LessonOpenBatchReq;
import com.jumper.study.db.model.StudentLesson;
import com.jumper.study.db.model.StudentLessonLog;

@Service
public class StudentLessonServiceImpl extends ServiceImpl<StudentLessonMapper, StudentLesson> implements StudentLessonService {
    //默认课程有效期1年，可设置
    @Value("${study-setting.lesson.limit:1}")
    private Long defaultLimitYear;

    @Autowired
    private StudentLessonLogService studentLessonLogService;

    @Override
    public IPage<StudentLessonDto> pageSearchWithAccountAndLesson(IPage<StudentLessonDto> page,
            EducationSearchReq req) {
        StudentLessonSearchDto search = new StudentLessonSearchDto();
        search.setAccountId(req.getAccountId());
        search.setStudentName(req.getStudentName());
        search.setLessonId(req.getLessonId());
        search.setLesson(req.getLessonTitle());
        search.setOpenStartDate(req.getOpenStartDate());
        search.setOpenEndDate(req.getOpenEndDate());
        search.setSort(new SortField("id", SortType.DESC));

        return getBaseMapper().pageListWithStudentAndLesson(page, search);
    }

    @Override
    public IPage<StudentLessonDto> pageSearchWithLessonByAccountId(IPage<StudentLessonDto> page, Long accountId) {
        StudentLessonSearchDto search = new StudentLessonSearchDto();
        search.setAccountId(accountId);
        search.setSort(new SortField("study_times", SortType.DESC));

        return getBaseMapper().pageListWithStudentAndLesson(page, search);
    }

    @Override
    public IPage<StudentLessonDto> pageSearchWithAccountByLessonId(IPage<StudentLessonDto> page, Long lessonId) {
        StudentLessonSearchDto search = new StudentLessonSearchDto();
        search.setLessonId(lessonId);
        search.setSort(new SortField("study_times", SortType.DESC));

        return getBaseMapper().pageListWithStudentAndLesson(page, search);
    }

    @Override
    @Transactional
    public boolean openLesson(StudentLesson entity) {
        //查询是否开通过，并重新设置有效期
        StudentLesson sLesson = getByAccountAndLessonId(entity.getAccountId(), entity.getLessonId());
        if (sLesson == null) {
            entity.setExpireTime(LocalDate.now().plusYears(defaultLimitYear));
            boolean result = saveOrUpdate(entity);
            if (result) {
                StudentLessonLog slLog = new StudentLessonLog();
                slLog.setAdminId(entity.getAdminId());
                slLog.setLessonId(entity.getLessonId());
                slLog.setAccountId(entity.getAccountId());
                slLog.setOperate("课程重新开通");
                studentLessonLogService.save(slLog);
            }
            return result;
        }

        sLesson.setExpireTime(LocalDate.now().plusYears(defaultLimitYear));
        boolean result = updateById(sLesson);
        if (result) {
            StudentLessonLog slLog = new StudentLessonLog();
            slLog.setLessonId(sLesson.getLessonId());
            slLog.setAccountId(sLesson.getAccountId());
            slLog.setAdminId(sLesson.getAdminId());
            slLog.setOperate("已有课程重新开通");
            studentLessonLogService.save(slLog);
        }
        return result;
    }

    @Override
    @Async("async")
    @Transactional
    public void openLessonBatch(LessonOpenBatchReq req, Long adminId) {
        List<Long> accountIds = req.getAccountIds();
        List<Long> lessonIds = req.getLessonIds();
        
        LambdaQueryWrapper<StudentLesson> wrapper = Wrappers.lambdaQuery();
        wrapper.in(StudentLesson::getAccountId, accountIds);
        wrapper.in(StudentLesson::getLessonId, lessonIds);
        Map<String, StudentLesson> maps = list(wrapper).stream()
                .collect(Collectors.toMap(
                    sl -> String.format("%s-%s", sl.getAccountId(), sl.getLessonId()),
                    sl -> sl)
                );
        List<StudentLesson> updates = new ArrayList<>();
        List<StudentLessonLog> slLogs = new ArrayList<>();
        for(Long accountId : accountIds) {
            for (Long lessonId : lessonIds) {
                String key = String.format("%s-%s", accountId, lessonId);
                StudentLesson entity = null;
                StudentLessonLog slLog = new StudentLessonLog();
                if (maps.containsKey(key)) {
                    entity = maps.get(key);
                    entity.setExpireTime(LocalDate.now().plusYears(defaultLimitYear));
                    entity.setAdminId(adminId);
                    slLog.setAccountId(entity.getAccountId());
                    slLog.setLessonId(entity.getLessonId());
                    slLog.setAdminId(adminId);
                    slLog.setOperate("已有课程重新开通");
                } else {
                    entity = new StudentLesson();
                    entity.setAccountId(accountId);
                    entity.setLessonId(lessonId);
                    entity.setOrderId(0l);
                    entity.setAdminId(adminId);
                    entity.setExpireTime(LocalDate.now().plusYears(defaultLimitYear));
                    slLog.setAccountId(accountId);
                    slLog.setLessonId(lessonId);
                    slLog.setAdminId(adminId);
                    slLog.setOperate("课程开通");
                }
                
                updates.add(entity);
                slLogs.add(slLog);
            }
        }

        boolean result = saveOrUpdateBatch(updates);
        if (result) {
            studentLessonLogService.saveBatch(slLogs);
        }
    }

    @Override
    public boolean closeLesson(Long orderId, Long adminId) {
        LambdaQueryWrapper<StudentLesson> query = Wrappers.lambdaQuery();
        query.eq(StudentLesson::getOrderId, orderId);
        List<StudentLesson> sLessons = list(query);
        List<StudentLessonLog> slLogs = new ArrayList<>(sLessons.size());
        for(StudentLesson sLesson : sLessons) {
            StudentLessonLog slLog = new StudentLessonLog();
            slLog.setAccountId(sLesson.getAccountId());
            slLog.setLessonId(sLesson.getLessonId());
            slLog.setAdminId(adminId);
            slLog.setOperate("关闭课程");
            slLogs.add(slLog);
        }

        LambdaUpdateWrapper<StudentLesson> wrapper = Wrappers.lambdaUpdate();
        wrapper.set(StudentLesson::getExpireTime, LocalDate.now().minusDays(1));
        wrapper.eq(StudentLesson::getOrderId, orderId);
        Integer ret = getBaseMapper().update(wrapper);
        boolean result = SqlHelper.retBool(ret);
        if (result) {
            studentLessonLogService.saveBatch(slLogs);
        }
        return result;
    }

    @Override
    public boolean closeLesson(StudentLesson entity) {
        entity.setExpireTime(LocalDate.now().minusDays(1));
        boolean result = updateById(entity);

        StudentLessonLog slLog = new StudentLessonLog();
        slLog.setLessonId(entity.getLessonId());
        slLog.setAccountId(entity.getAccountId());
        slLog.setAdminId(entity.getAdminId());
        slLog.setOperate("关闭课程");
        studentLessonLogService.save(slLog);
        return result;
    }

    @Override
    public StudentLesson getByAccountAndLessonId(Long accountId, Long lessonId) {
        LambdaQueryWrapper<StudentLesson> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(StudentLesson::getAccountId, accountId);
        wrapper.eq(StudentLesson::getLessonId, lessonId);
        wrapper.last("limit 1");

        return getOne(wrapper);
    }

    @Override
    public StudentLesson getByAccountAndLessonId(Long accountId, Long lessonId, boolean expired) {
        LambdaQueryWrapper<StudentLesson> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(StudentLesson::getAccountId, accountId);
        wrapper.eq(StudentLesson::getLessonId, lessonId);
        if (expired) {
            wrapper.lt(StudentLesson::getExpireTime, LocalDate.now());
        } else {
            wrapper.ge(StudentLesson::getExpireTime, LocalDate.now());
        }
        wrapper.last("limit 1");
        
        return getOne(wrapper);
    }

    @Override
    public boolean plusExpireTimeById(StudentLesson entity) {
        entity.setExpireTime(entity.getExpireTime().plusYears(defaultLimitYear));
        return updateById(entity);
    }
    
}
